package state

import (
	"alex/ptp1588boundaryclock/datasets"
	"alex/ptp1588boundaryclock/datatypes"
)

// Data comparison algorithm as described in 9.3.4 and fig27
// returns the better set
// TODO: better by topology - maybe (bool bool) useful after all...
func DataSetComparison(setA datasets.BMCDataset, setB datasets.BMCDataset) (bool, bool) {
	identA, identB := compareIdentity(setA.GetIdentity(), setB.GetIdentity())
	if identA && identB {
		// Figure 28
		if setA.GetStepsRemoved() > setB.GetStepsRemoved()+1 {
			return true, false
		} else if setA.GetStepsRemoved()+1 < setB.GetStepsRemoved() {
			return false, true
		}
		if setA.GetStepsRemoved() > setB.GetStepsRemoved() {
		return compareIdentityofReceiverAndSender(setA.GetIdentityOfReceiver(), setA.GetIdentityOfSender())
	} else if setA.GetStepsRemoved() < setB.GetStepsRemoved() {
		return compareIdentityofReceiverAndSender(setB.GetIdentityOfReceiver(), setB.GetIdentityOfSender())
	}
		a, b := compareIdentity(setA.GetIdentityOfSender(), setB.GetIdentityOfSender())
		if !(a && b) {
			return a, b
		}
		if setA.GetPortNumberOfReceiver() > setB.GetPortNumberOfReceiver() {
			return false, true
		} else if setA.GetPortNumberOfReceiver() < setB.GetPortNumberOfReceiver() {
			return true, false
		}
	}
	if setA.GetPriority1() > setB.GetPriority1() {
		return false, true
	} else if setA.GetPriority1() < setB.GetPriority1() {
		return true, false
	}
	if setA.GetQuality().ClockClass > setB.GetQuality().ClockClass {
		return false, true
	} else if setA.GetQuality().ClockClass < setB.GetQuality().ClockClass {
		return true, false
	}
	if setA.GetQuality().ClockAccuracy > setB.GetQuality().ClockAccuracy {
		return false, true
	} else if setB.GetQuality().ClockAccuracy < setB.GetQuality().ClockAccuracy {
		return true, false
	}
	if setA.GetQuality().OffsetScaledVarianceLog > setB.GetQuality().OffsetScaledVarianceLog {
		return false, true
	} else if setA.GetQuality().OffsetScaledVarianceLog < setB.GetQuality().OffsetScaledVarianceLog {
		return true, false
	}
	if setA.GetPriority2() > setB.GetPriority2() {
		return false, true
	} else if setA.GetPriority2() < setB.GetPriority2() {
		return true, false
	}
	if identA {
		return true, false
	} else if identB {
		return false, true
	}
	return false, false
}

func compareIdentityofReceiverAndSender(identityA *datatypes.ClockIdentity, identityB *datatypes.ClockIdentity) (bool, bool) {
	a1, a2 := compareIdentity(identityA, identityB)
	if a1 && a2 {
		return false, false
	} else if a1 {
		return false, true
	} else if a2 {
		return true, false
	}
	return false, false
}

// compares two clock identities
func compareIdentity(identityA *datatypes.ClockIdentity, identityB *datatypes.ClockIdentity) (bool, bool) {
	for key, _ := range identityA {
		if identityA[key] > identityB[key] {
			return false, true
		} else if identityA[key] < identityB[key] {
			return true, false
		}
	}
	// identity is equal
	return true, true
}
